package com.zhoug.android.common.file;

import android.content.Context;
import android.content.Intent;
import android.media.MediaMetadataRetriever;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;

import com.zhoug.android.common.utils.LogUtils;

import java.io.File;
import java.io.IOException;
import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;

import androidx.annotation.NonNull;

/**
 * 文件存储访问工具
 * @Author: zhoug
 * @Date: 2022/9/1
 * @Description:
 */
public class FileUtils {
    private static final String TAG = ">>>FileUtils";

    /**
     * 获取文件名(包括后缀名)
     *
     * @param file
     * @return
     */
    public static String getFileName(File file) {
        if (file == null) {
            LogUtils.e(TAG, "getFileName:file is null");
            return null;
        }
        return file.getName();
    }

    /**
     * 获取文件名(包括后缀名)
     *
     * @param path
     * @return
     */
    public static String getFileName(String path) {
        if (path == null) {
            LogUtils.e(TAG, "getFileName:path is null");
            return null;
        }
        return getFileName(new File(path));
    }

    /**
     * 获取文件名(不包括后缀)
     *
     * @param file
     * @return
     */
    public static String getFileNameNoSuffix(File file) {
        if (file == null) {
            LogUtils.e(TAG, "getFileNameNoSuffix:file is null");
            return null;
        }
        //文件夹
        if (file.isDirectory()) {
            return file.getName();
        }
        String nameWithType = getFileName(file);
        if (nameWithType != null) {
            int endIndex = nameWithType.lastIndexOf(".");
            if (endIndex >= 0 && endIndex < nameWithType.length()) {
                return nameWithType.substring(0, endIndex);
            } else {
                return nameWithType;
            }
        } else {
            return null;
        }
    }


    /**
     * 获取文件名(不包括后缀)
     *
     * @param path
     * @return
     */

    public static String getFileNameNoSuffix(String path) {
        if (path == null) {
            LogUtils.e(TAG, "getFileNameNoSuffix:path is null");
            return null;
        }
        return getFileNameNoSuffix(new File(path));
    }

    /**
     * @param file
     * @param includeSpot 是否包含"." true:".png" ; false:"png"
     * @return
     */
    public static String getFileSuffix(File file, boolean includeSpot) {
        if (file != null && file.isDirectory()) {
            return null;
        }
        String name = getFileName(file);
        if (name != null && name.length() > 0) {
            int endIndex = name.lastIndexOf(".");
            if (endIndex >= 0 && endIndex < name.length()) {
                return name.substring(includeSpot ? endIndex : endIndex + 1);
            }
        }
        return null;
    }

    /**
     * 获取文件的后缀
     *
     * @param file
     * @return "png" 不包含"."
     */
    public static String getFileSuffix(File file) {
        return getFileSuffix(file,false);
    }

    /**
     * 获取文件的后缀(doc,png...)
     *
     * @param path
     * @return
     */
    public static String getFileSuffix(String path,boolean includeSpot) {
        if (path == null) {
            LogUtils.e(TAG, "getFileSuffix:path is null");
            return null;
        }
        return getFileSuffix(new File(path),includeSpot);
    }

    /**
     * 获取文件的后缀(doc,png...)
     *
     * @param path
     * @return "doc"
     */
    public static String getFileSuffix(String path) {
        if (path == null) {
            LogUtils.e(TAG, "getFileSuffix:path is null");
            return null;
        }
        return getFileSuffix(new File(path),false);
    }

    /**
     * 外部存储是否可用
     *
     * @return
     */
    public static boolean isExternalStorageEnable() {
        boolean equals = Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
        if (!equals) {
            LogUtils.e(TAG, "isExternalStorageEnable:外部存储不可用");
        }
        return equals;
    }

    /**
     * 获取外部储存公用目录
     *
     * @param type
     * @return
     */
    public static File getExternalStoragePublicDirectory(String type) {
        if (isExternalStorageEnable()) {
            File publicDirectory = Environment.getExternalStoragePublicDirectory(type);
            if (publicDirectory != null) {
                if (!publicDirectory.exists()) {
                    if (mkdirs(publicDirectory)) {
                        return publicDirectory;
                    }
                } else {
                    return publicDirectory;
                }
            } else {
                LogUtils.e(TAG, "获取外部储存公用目录失败:type=" + type);
            }
        }
        return null;
    }

    /**
     * 获取外部储存根目录 读写文件需要权限
     *
     * @return eg:/storage/emulated/0
     */
    public static File getExternalRoot() {
        if (isExternalStorageEnable()) {
            File externalStorageDirectory = Environment.getExternalStorageDirectory();
            if (externalStorageDirectory == null) {
                LogUtils.e(TAG, "获取外部储存根目录失败");
            }
            return externalStorageDirectory;
        }
        return null;
    }

    /**
     * 获取外部储存根目录下的子目录 读写文件需要权限
     *
     * @param folder
     * @return eg:/storage/emulated/0/folder
     */
    public static File getExternalFolder(String folder) {
        if (folder == null) {
            LogUtils.e(TAG, "getExternalFolder: folder is null");
            return null;
        }
        File externalRoot = getExternalRoot();
        if (null != externalRoot) {
            return createDirectory(externalRoot, folder);
        }
        return null;
    }
    /**
     * 获取App内部存储根目录:
     * 文件默认私有的，即别的应用不能访问，本应用卸载则文件删除
     * 读写文件无需权限
     *
     * @param context
     * @return /data/user/0/package/
     */
    public static File getAppDataRoot(@NonNull Context context) {
        File root;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            root = context.getDataDir();
        } else {
            root = context.getFilesDir().getParentFile();
        }
        if (null == root) {
            LogUtils.e(TAG, "获取App内部存储根目录失败");
        }
        return root;
    }

    /**
     * 获取App内部存储根目录下的子目录
     * 读写文件无需权限
     *
     * @param folder
     * @return /data/user/0/package/folder
     */
    public static File getAppDataFolder(@NonNull Context context, String folder) {
        if (folder == null) {
            LogUtils.e(TAG, "getAppDataFolder:folder is null");
            return null;
        }
        File externalRoot = getAppDataRoot(context);
        if (externalRoot != null) {
            return createDirectory(externalRoot, folder);
        }
        return null;
    }

    /**
     * 获取App外部储存根目录
     * 只能本应用访问，应用删除文件删除
     * 读写文件无需权限
     *
     * @return /storage/emulated/0/Android/data/package
     */
    public static File getAppExternalRoot(@NonNull Context context) {
        File externalCacheDir = context.getExternalCacheDir();
        if (externalCacheDir != null) {
            return externalCacheDir.getParentFile();
        } else {
            LogUtils.e(TAG, "获取App外部储存根目录失败");
        }
        return null;
    }

    /**
     * 获取App外部储存根目录下的子目录
     * 只能本应用访问，应用删除文件删除
     * 读写文件无需权限
     *
     * @return /storage/emulated/0/Android/data/package/folder
     */
    public static File getAppExternalFolder(@NonNull Context context, String folder) {
        if (folder == null) {
            LogUtils.e(TAG, "getAppExternalFolder:folder is null");
            return null;
        }
        File externalRoot = getAppExternalRoot(context);
        if (null != externalRoot) {
            return createDirectory(externalRoot, folder);
        }
        return null;
    }

    /**
     * 创建文件夹
     *
     * @param file
     * @return 是否创建成功
     */
    public static boolean createDirectory(File file) {
        if (file == null) {
            LogUtils.e(TAG, "createDirectory:file is null");
            return false;
        }
        if (!file.exists()) {
            return mkdirs(file);
        } else {
            return true;//文件夹存在
        }
    }

    public static boolean mkdirs(File file) {
        if (file == null) {
            LogUtils.e(TAG, "mkdirs:file is null");
            return false;
        }
        boolean success = file.mkdirs();
        if (!success) {
            LogUtils.e(TAG, "mkdirs:创建文件夹失败" + file.getAbsolutePath());
        }
        return success;
    }

    /**
     * 创建文件夹
     *
     * @param parent
     * @param folder
     * @return 是否创建成功
     */
    public static File createDirectory(File parent, String folder) {
        if (parent == null || folder == null) {
            LogUtils.e(TAG, "createDirectory:parent or folder is null");
            return null;
        }
        File file = new File(parent, folder);
        if (!file.exists()) {
            return mkdirs(file) ? file : null;
        } else {
            return file;//文件夹存在
        }
    }
    /**
     * 创建文件夹
     *
     * @param path
     * @return 是否创建成功
     */
    public static boolean createDirectory(String path) {
        return path != null && createDirectory(new File(path));
    }


    /**
     * 创建文件
     *
     * @param file
     * @return 是否创建成功
     */
    public static boolean createFile(File file) {
        if (file == null) {
            LogUtils.e(TAG, "createFile:file is null");
            return false;
        }
        File parentFile = file.getParentFile();
        //父目录不存在
        if (!parentFile.exists()) {
            boolean success = mkdirs(parentFile);
            if (success) {
                try {
                    return file.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                    LogUtils.e(TAG, "createFile:创建文件失败:" + file.getAbsolutePath());
                }
            }
        } else {
            try {
                return file.exists() || file.createNewFile();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return false;
    }

    /**
     * 创建文件
     *
     * @param path
     * @return 是否创建成功
     */
    public static boolean createFile(String path) {
        return path != null && createFile(new File(path));
    }

    /**
     * 获取文件 自动创建文件夹
     *
     * @param absRootPath 根目录绝对路径
     * @param folderPath  相对于根目录的文件夹路径
     * @param fileName    文件名字
     * @return
     */
    public static File getFile(String absRootPath, String folderPath, String fileName) {
        File folder = new File(absRootPath, folderPath);
        if (!folder.exists()) {
            boolean success = mkdirs(folder);
            if (success) {
                return new File(folder, fileName);
            }
        } else {
            return new File(folder, fileName);
        }
        return null;
    }
    /**
     * 获取文件 自动创建文件夹
     *
     * @param parentPath 父路径
     * @param filePath   文件路径
     * @return
     */
    public static File getFile(String parentPath, String filePath) {
        File file = new File(parentPath, filePath);
        if (!file.getParentFile().exists()) {
            boolean success = mkdirs(file.getParentFile());
            if (success) {
                return file;
            }
        } else {
            return file;
        }
        return null;
    }


    /**
     * 获取外部储存根目录下的文件,自动创建文件夹
     *
     * @param folderPath 文件夹 相对路径
     * @param fileName   文件文字
     * @return
     */
    public static File getExternalFile(String folderPath, String fileName) {
        if (isExternalStorageEnable()) {
            File externalRoot = getExternalRoot();
            return externalRoot != null ? getFile(externalRoot.getAbsolutePath(), folderPath, fileName) : null;
        } else {
            return null;
        }
    }

    /**
     * 获取外部储存根目录下的文件 自动创建文件夹
     *
     * @param path 文件路径:相对路径
     * @return
     */
    public static File getExternalFile(String path) {
        if (isExternalStorageEnable()) {
            File externalRoot = getExternalRoot();
            return externalRoot != null ? getFile(externalRoot.getAbsolutePath(), path) : null;
        }
        return null;
    }

    /**
     * 获取App外部储存根目录下的文件,自动创建文件夹
     *
     * @param folderPath context
     * @param folderPath 文件夹 相对路径
     * @param fileName   文件文字
     * @return
     */
    public static File getAppExternalFile(@NonNull Context context, String folderPath, String fileName) {
        if (isExternalStorageEnable()) {
            File appExternalRoot = getAppExternalRoot(context);
            return appExternalRoot != null ? getFile(appExternalRoot.getAbsolutePath(), folderPath, fileName) : null;
        } else {
            return null;
        }
    }


    /**
     * 获取App外部储存根目录下的文件,自动创建文件夹
     *
     * @param context
     * @param path    文件路径:相对路径
     * @return
     */
    public static File getAppExternalFile(@NonNull Context context, String path) {
        if (isExternalStorageEnable()) {
            File appExternalRoot = getAppExternalRoot(context);
            return appExternalRoot != null ? getFile(appExternalRoot.getAbsolutePath(), path) : null;
        }
        return null;
    }


    /**
     * 获取App内部储存根目录下的文件,自动创建文件夹
     *
     * @param folderPath context
     * @param folderPath 文件夹 相对路径
     * @param fileName   文件文字
     * @return
     */
    public static File getAppInternalFile(@NonNull Context context, String folderPath, String fileName) {
        if (isExternalStorageEnable()) {
            File appDataRoot = getAppDataRoot(context);
            return appDataRoot != null ? getFile(appDataRoot.getAbsolutePath(), folderPath, fileName) : null;
        } else {
            return null;
        }
    }


    /**
     * 获取App内部储存根目录下的文件,自动创建文件夹
     *
     * @param context
     * @param path    文件路径:相对路径
     * @return
     */
    public static File getAppInternalFile(@NonNull Context context, String path) {
        if (isExternalStorageEnable()) {
            File appDataRoot = getAppDataRoot(context);
            return appDataRoot != null ? getFile(appDataRoot.getAbsolutePath(), path) : null;
        }
        return null;
    }

    /**
     * 获取App外部缓存
     *
     * @param folder 缓存目录 为null时表示缓存根目录
     * @return
     */
    public static File getAppExternalCacheDir(@NonNull Context context, String folder) {
        File cacheDir = context.getExternalCacheDir();
        File file = cacheDir;
        if (folder != null) {
            file = new File(cacheDir, folder);
        }
        if (file != null) {
            if (!file.exists()) {
                if (mkdirs(file)) {
                    return file;
                }
            } else {
                return file;
            }
        }
        return null;
    }


    /**
     * 获取App外部私有存储指定类型的目录
     *
     * @param context
     * @param type
     * @return
     */
    public static File getAppExternalFilesDir(@NonNull Context context, String type) {
        File externalFilesDir = context.getExternalFilesDir(type);
        if (createDirectory(externalFilesDir)) {
            return externalFilesDir;
        }
        return null;
    }

    /**
     * 获取应用内部缓存目录
     *
     * @param context
     * @return
     */
    public static File getAppCacheDir(@NonNull Context context) {
        File cacheDir = context.getCacheDir();
        if (createDirectory(cacheDir)) {
            return cacheDir;
        }
        return null;
    }

    /**
     * 获取应用内部缓存目录
     *
     * @param context
     * @return
     */
    public static File getAppCacheDir(@NonNull Context context, String folder) {
        File cacheDir = context.getCacheDir();
        if (cacheDir != null) {
            File result = new File(cacheDir, folder);
            if (createDirectory(result)) {
                return result;
            } else {
                return null;
            }
        }
        return null;
    }

    /**
     * 拍摄照片和视频后相册中没有文件，的解决办法
     *
     * @param context
     * @param path
     */
    public static void scannerFile(@NonNull Context context, String path) {
        Intent intent = new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE);
        Uri uri = Uri.fromFile(new File(path));
        intent.setData(uri);
        context.sendBroadcast(intent);
    }

    /**
     * 获取文件夹下面所有文件的大小
     *
     * @param file
     * @return
     */
    public static long getFileSize(File file) {
        if (!file.exists()) {
            return 0;
        }
        long size = 0;
        if (file.isFile()) {
            return file.length();
        } else {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File file1 : files) {
                    size += getFileSize(file1);
                }
            }
        }
        return size;
    }

    /**
     * 把字节大小转化为 以B\K\M... 为单位
     *
     * @param size
     * @return
     */
    public static String getFormatFileSize(long size) {
//        Log.d(TAG, "getFormatSize: size="+size);
        double kb = size / 1024.0;
        if (kb < 1) {
            return size + "B";
        }

        double mb = kb / 1024.0;
        if (mb < 1) {
            BigDecimal result1 = new BigDecimal(Double.toString(kb));
            return result1.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "K";
        }

        double gb = mb / 1024.0;
        if (gb < 1) {
            BigDecimal result2 = new BigDecimal(Double.toString(mb));
            return result2.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "M";
        }

        double tb = gb / 1024.0;
        if (tb < 1) {
            BigDecimal result3 = new BigDecimal(Double.toString(gb));
            return result3.setScale(2, BigDecimal.ROUND_HALF_UP)
                    .toPlainString() + "GB";
        }
        BigDecimal result4 = new BigDecimal(tb);
        return result4.setScale(2, BigDecimal.ROUND_HALF_UP).toPlainString()
                + "TB";
    }

    /**
     * 获取app外部和内部缓存大小
     *
     * @param context
     * @return
     */
    public static String getAppCacheSize(@NonNull Context context) {
        long size = 0;
        //外部存储的缓存
        if (isExternalStorageEnable()) {
            File externalCacheDir = context.getExternalCacheDir();
            if (externalCacheDir != null && externalCacheDir.exists()) {
                size += getFileSize(externalCacheDir);
            }
        }
        //内部存储的缓存
        File cacheDir = context.getCacheDir();
        if (cacheDir != null && cacheDir.exists()) {
            size += getFileSize(cacheDir);
        }
        return getFormatFileSize(size);
    }

    /**
     * 删除文件/或文件夹下所有文件
     *
     * @param file
     */
    public static boolean deleteFile(File file) {
        if (!file.exists()) {
            return true;
        }
        if (file.isFile()) {
//            Log.d(TAG, "deleteFile: ");
            return file.delete();

        } else {
            File[] files = file.listFiles();
            if (files != null && files.length > 0) {
                for (File file1 : files) {
                    deleteFile(file1);
                }
            }
        }
        return true;
    }

    /**
     * 清除app的缓存[外部存储的缓存:context.getExternalCacheDir+内部存储的缓存:context.getCacheDir()]
     */
    public static void deleteAppCache(@NonNull Context context) {
        //外部存储的缓存
        if (isExternalStorageEnable()) {
            File externalCacheDir = context.getExternalCacheDir();
            if (externalCacheDir != null && externalCacheDir.exists()) {
                deleteFile(externalCacheDir);
            }
        }
        //内部存储的缓存
        File cacheDir = context.getCacheDir();
        if (cacheDir != null && cacheDir.exists()) {
            deleteFile(cacheDir);
        }
    }

    /**
     * 获取音视频文件的播放长度
     *
     * @param videoPath
     * @return
     */
    public static int getVideoDuration(String videoPath) {
        if (videoPath == null) {
            return 0;
        }
        int duration;
        try {
            MediaMetadataRetriever mmr = new MediaMetadataRetriever();
            mmr.setDataSource(videoPath);
            duration = Integer.parseInt(mmr.extractMetadata
                    (MediaMetadataRetriever.METADATA_KEY_DURATION));
        } catch (Exception e) {
            e.printStackTrace();
            return 0;
        }
        return duration;
    }

    /**
     * 递归获取文件目录下的指定后缀的文件
     *
     * @param folder 目录
     * @param suffix 后缀 (doc,png...)null表示所有文件
     * @return
     */
    public static List<String> findFiles(String folder, String... suffix) {
        if (folder == null) {
            return null;
        }
        //结果
        List<String> result = new ArrayList<>();
        File f = new File(folder);
        if (f.exists()) {
            File[] files = f.listFiles();
            if (files != null && files.length > 0) {
                for (File child : files) {
                    if (child.exists()) {
                        //是文件
                        if (child.isFile()) {
                            if (suffix != null) {
                                for (String s : suffix) {
                                    if (s.equals(getFileSuffix(child))) {
                                        result.add(child.getAbsolutePath());
                                    }
                                }
                            } else {
                                result.add(child.getAbsolutePath());
                            }
                        } else {
                            //是目录
                            List<String> paths = findFiles(child.getAbsolutePath(), suffix);
                            if (paths != null && paths.size() > 0) {
                                result.addAll(paths);
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

    /**
     * 递归获取文件目录下的指定后缀的文件
     *
     * @param folder   文件目录
     * @param fileType {@link FileType}
     * @return
     */
    public static List<String> findFiles(String folder, int fileType) {
        if (folder == null) {
            return null;
        }
        //结果
        List<String> result = new ArrayList<>();
        File f = new File(folder);
        if (f.exists()) {
            File[] files = f.listFiles();
            if (files != null && files.length > 0) {
                for (File child : files) {
                    if (child.exists()) {
                        //是文件
                        if (child.isFile()) {
                            if (fileType != FileType.ALL) {
                                if (fileType == FileType.getType(child.getAbsolutePath())) {
                                    result.add(child.getAbsolutePath());
                                }
                            } else {
                                result.add(child.getAbsolutePath());
                            }
                        } else {
                            //是目录
                            List<String> paths = findFiles(child.getAbsolutePath(), fileType);
                            if (paths != null && paths.size() > 0) {
                                result.addAll(paths);
                            }
                        }
                    }
                }
            }
        }
        return result;
    }

}
